package com.swingson.properties.specificclass_impl;

import com.swingson.Swingson;
import com.swingson.SwingsonGui;
import com.swingson.jsonparser.JsonElement;
import com.swingson.other.ConditionAndAction;
import com.swingson.other.MethodExecutor;
import com.swingson.properties.AbstractAssignMethodPropertyProcessor;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.FocusListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JComponent;

/**
 * @author sad
 */
public class ComponentListenerPropertyProcessor extends AbstractAssignMethodPropertyProcessor {

    public static final String onHidden = "onHidden";
    public static final String onResized = "onResized";
    public static final String onMoved = "onMoved";
    public static final String onShown = "onShown";

    static List<Class[]> argumentsVariants = new ArrayList<Class[]>() {
        {
            add(new Class[]{});
            add(new Class[]{String.class});//param string
        }
    };

    @Override
    protected String getName() {
        return "Focus Event Listener";
    }

    @Override
    protected List<Class[]> methodArgumentsVariants() {
        return argumentsVariants;
    }

    @Override
    protected void attachMethod(JsonElement jsonElement, final JComponent component, final SwingsonGui gui, String propertyName, final MethodExecutor method, final int methodArgumentVariant, final ConditionAndAction conditionAndAction) {
        EventExecutor<ComponentEvent> executor = new EventExecutor<ComponentEvent>() {
            @Override
            public void execute(ComponentEvent event) {
                if (!Swingson.isEnabledUserInput()) {
                    return;
                }
                try {
                    switch (methodArgumentVariant) {
                        case 0:
                            method.invoke();
                            break;
                        case 1:
                            method.invoke(event.paramString());
                            break;
                    }
                    runAction(conditionAndAction, gui, component);
                } catch (Throwable ex) {
                    onError(gui, ex);
                }
            }
        };
        for (FocusListener listener : component.getFocusListeners()) {
            if (listener instanceof ComponentListenerWrapper) {
                ComponentListenerWrapper lw = (ComponentListenerWrapper) listener;
                switch (propertyName) {
                    case onHidden:
                        lw.setOnHidden(executor);
                        break;
                    case onMoved:
                        lw.setOnMoved(executor);
                        break;
                    case onResized:
                        lw.setOnResized(executor);
                        break;
                    case onShown:
                        lw.setOnShown(executor);
                        break;

                }

                return;
            }
        }

        ComponentListenerWrapper listener = new ComponentListenerWrapper();
        switch (propertyName) {
            case onHidden:
                listener.setOnHidden(executor);
                break;
            case onMoved:
                listener.setOnMoved(executor);
                break;
            case onResized:
                listener.setOnResized(executor);
                break;
            case onShown:
                listener.setOnShown(executor);
                break;
        }

        component.addComponentListener(listener);
    }

    private static class ComponentListenerWrapper implements ComponentListener {

        private EventExecutor<ComponentEvent> onResized;
        private EventExecutor<ComponentEvent> onMoved;
        private EventExecutor<ComponentEvent> onShown;
        private EventExecutor<ComponentEvent> onHidden;

        public void setOnResized(EventExecutor<ComponentEvent> onResized) {
            this.onResized = onResized;
        }

        public void setOnMoved(EventExecutor<ComponentEvent> onMoved) {
            this.onMoved = onMoved;
        }

        public void setOnShown(EventExecutor<ComponentEvent> onShown) {
            this.onShown = onShown;
        }

        public void setOnHidden(EventExecutor<ComponentEvent> onHidden) {
            this.onHidden = onHidden;
        }

        @Override
        public void componentResized(ComponentEvent e) {
            if (onResized != null) {
                onResized.execute(e);
            }
        }

        @Override
        public void componentMoved(ComponentEvent e) {
            if (onMoved != null) {
                onMoved.execute(e);
            }
        }

        @Override
        public void componentShown(ComponentEvent e) {
            if (onShown != null) {
                onShown.execute(e);
            }
        }

        @Override
        public void componentHidden(ComponentEvent e) {
            if (onHidden != null) {
                onHidden.execute(e);
            }
        }
    }
}
